package com.baijiaoxi.utils.email;

import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.dm.model.v20151123.SingleSendMailRequest;
import com.aliyuncs.dm.model.v20151123.SingleSendMailResponse;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.exceptions.ServerException;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.baijiaoxi.common.model.Email;
import com.baijiaoxi.common.model.base.CommonError;
import com.baijiaoxi.common.model.base.CoreException;
import lombok.extern.slf4j.Slf4j;
import microsoft.exchange.webservices.data.core.ExchangeService;
import microsoft.exchange.webservices.data.core.enumeration.property.BodyType;
import microsoft.exchange.webservices.data.core.service.item.EmailMessage;
import microsoft.exchange.webservices.data.credential.ExchangeCredentials;
import microsoft.exchange.webservices.data.credential.WebCredentials;
import microsoft.exchange.webservices.data.property.complex.MessageBody;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;
import java.util.Properties;

@Slf4j
public class EmailSender {

    private EmailConfig emailConfig;
    private MimeMessage mimeMessage;
    private JavaMailSenderImpl sender;
    private SingleSendMailRequest aliMailRequest;
    private IAcsClient iAcsClient;
    private EmailMessage exchangeEmailMessage;

    public static void test(EmailConfig config, Email email) {
        new EmailSender().createMailSender(config).sendHtmlMail(email);
    }

    /**
     * 邮件发送器
     * smtp
     *
     * @return 配置好的工具
     */
    public EmailSender createMailSender(EmailConfig emailConfig) {
        this.emailConfig = emailConfig;
        if (emailConfig.getProtocol().equalsIgnoreCase("exchange")) {

            ExchangeService service = new ExchangeService(emailConfig.getExchangeVersion());
            ExchangeCredentials credentials = emailConfig.getDomain() == null || emailConfig.getDomain().isEmpty() ?
                    new WebCredentials(emailConfig.getUsername(), emailConfig.getPassword())
                    : new WebCredentials(emailConfig.getUsername(), emailConfig.getPassword(), emailConfig.getDomain());

            service.setCredentials(credentials);
            try {
                service.setUrl(new URI(emailConfig.getHost()));
            } catch (URISyntaxException e) {
                throw CoreException.create(CommonError.illegalExchangeHost, e);
            }
            try {
                this.exchangeEmailMessage = new EmailMessage(service);
            } catch (Exception e) {
                throw CoreException.create(CommonError.unableCreateEmailByExchange, e);
            }
        } else if (emailConfig.getProtocol().equalsIgnoreCase("ali-directmail")) {
            IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", emailConfig.getUsername(), emailConfig.getPassword());
            this.iAcsClient = new DefaultAcsClient(profile);
            this.aliMailRequest = new SingleSendMailRequest();
            aliMailRequest.setAccountName(emailConfig.getEamilFrom());
            aliMailRequest.setFromAlias(emailConfig.getEamilFromName());//发信人昵称，长度小于15个字符。
            aliMailRequest.setAddressType(1);//0：为随机账号 1：为发信地址
            aliMailRequest.setReplyToAddress(false);// 是否启用管理控制台中配置好回信地址（状态须验证通过），取值范围是字符串true或者false
            //SDK 采用的是http协议的发信方式, 默认是GET方法，有一定的长度限制。
            //若textBody、htmlBody或content的大小不确定，建议采用POST方式提交，避免出现uri is not valid异常
            aliMailRequest.setMethod(MethodType.POST);
        } else {
            JavaMailSenderImpl sender = new JavaMailSenderImpl();
            sender.setHost(this.emailConfig.getHost());
            sender.setPort(this.emailConfig.getPort());
            sender.setUsername(this.emailConfig.getUsername());
            sender.setPassword(this.emailConfig.getPassword());
            sender.setDefaultEncoding("Utf-8");
            Properties p = new Properties();
            p.setProperty("mail.smtp.timeout", this.emailConfig.getTimeout());
            p.setProperty("mail.smtp.auth", "false");
            p.setProperty("mail.smtp.port", String.valueOf(this.emailConfig.getPort()));
            p.setProperty("mail.smtp.socketFactory.port", String.valueOf(this.emailConfig.getPort()));
            p.put("mail.smtp.auth", "true");
            p.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
            sender.setJavaMailProperties(p);
            this.sender = sender;
            mimeMessage = sender.createMimeMessage();
        }
        return this;
    }


    /**
     * 发送邮件
     * 只发送一个人
     *
     * @param target  接受人
     * @param subject 主题
     * @param html    发送内容
     */
    public void sendHtmlMail(String target, String subject, String html) {
        try {
            if (iAcsClient != null) {
                aliMailRequest.setToAddress(target);
                //可以给多个收件人发送邮件，收件人之间用逗号分开，批量发信建议使用BatchSendMailRequest方式
                //request.setToAddress("邮箱1,邮箱2");
                aliMailRequest.setSubject(subject);
                //如果采用byte[].toString的方式的话请确保最终转换成utf-8的格式再放入htmlbody和textbody，若编码不一致则会被当成垃圾邮件。
                //注意：文本邮件的大小限制为3M，过大的文本会导致连接超时或413错误
                aliMailRequest.setHtmlBody(html);
                SingleSendMailResponse aliMailResponse = iAcsClient.getAcsResponse(aliMailRequest);
                log.debug("阿里云邮件推送requestId:{}", aliMailResponse.getRequestId());

            } else if (this.sender != null) {
                // 设置utf-8或GBK编码，否则邮件会有乱码
                MimeMessageHelper messageHelper = new MimeMessageHelper(this.mimeMessage, true, "UTF-8");
                messageHelper.setFrom(this.emailConfig.getEamilFrom(), this.emailConfig.getEamilFromName());
                messageHelper.setTo(target);
                messageHelper.setSubject(subject);
                messageHelper.setText(html, true);
                this.sender.send(this.mimeMessage);
            } else if (exchangeEmailMessage != null) {
                exchangeEmailMessage.setSubject(subject);
                MessageBody body = MessageBody.getMessageBodyFromText(html);
                body.setBodyType(BodyType.HTML);
                exchangeEmailMessage.setBody(body);
                exchangeEmailMessage.getToRecipients().add(target);
                exchangeEmailMessage.send();
            } else throw CoreException.create(CommonError.invalidEmailConfig, emailConfig, target, subject, html);
        } catch (ServerException e) {
            throw CoreException.create(CommonError.unableSendEmailCauseServer, e, emailConfig, target, subject, html);
        } catch (ClientException e) {
            throw CoreException.create(CommonError.unableSendEmailCauseClient, e, emailConfig, target, subject, html);
        } catch (Exception e) {
            throw CoreException.create(CommonError.unableSendEmailCauseOther, e, emailConfig, target, subject, html);
        }
    }

    /**
     * 发送邮件
     *
     * @param targetList 接受人：英文逗号分隔
     * @param subject    主题
     * @param html       发送内容
     * @throws MessagingException           异常
     * @throws UnsupportedEncodingException 异常
     */
    public void sendHtmlMailBatch(List<String> targetList, String subject, String html) {
        // 设置utf-8或GBK编码，否则邮件会有乱码
        int co = 0;
        for (int i = 0; i < targetList.size(); i++) {
            String target = targetList.get(i);
            if (target != null && !target.isEmpty()) {
                try {
                    this.sendHtmlMail(target, subject, html);
                    co++;
                } catch (Exception e) {
                    log.error("邮件发送失败", target, e);
                }
            }
        }
        if (co == 0)
            throw CoreException.create(CommonError.unableSendAllEmail);
        log.debug("批量邮件发送结果，共{},成功{}", targetList.size(), co);
    }

    /**
     * 发送邮件
     *
     * @param email 邮件
     */
    public void sendHtmlMail(Email email) {
        if (email.getTargetList() == null || email.getTargetList().isEmpty())
            sendHtmlMail(email.getTarget(), email.getSubject(), email.getHtml());
        else {
            if (this.aliMailRequest == null) {
                sendHtmlMailBatch(email.getTargetList(), email.getSubject(), email.getHtml());
            } else {
                String targets = String.join(",", email.getTargetList());
                sendHtmlMail(targets, email.getSubject(), email.getHtml());
            }
        }
    }
}
